home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Modules / BackSpaceModules / Source / MazeView / MazeView.m < prev    next >
Text File  |  1994-01-12  |  19KB  |  721 lines

  1. // MazeView by David Bau
  2. // Copyright 1994 by David Bau.  All rights reserved.
  3. //
  4. // I feel silly even saying this, but please don't charge for this
  5. // module or any product containing a portion or modification of it,
  6. // and when distributing, please give credit where credit is due.
  7. //
  8. // If you add anything to this module or derive anything interesting
  9. // from it, please let me know!
  10. //
  11. // I'll probably be bau@cs.cornell.edu for a while.
  12. //
  13. // David Bau 11/13/93
  14. // 777 South Avenue, Weston, MA 02193
  15.  
  16. #import <appkit/appkit.h>
  17. #import <defaults/defaults.h>
  18. #import <libc.h>
  19. #import <time.h>
  20. #import <dpsclient/wraps.h>
  21. #import "MazeView.h"
  22. #import "RandomIntPicker.h"
  23. #import "Thinker.h"
  24.  
  25.  
  26. static void ColorToString(NXColor color, char *str);
  27. static NXColor ColorFromString(const char *str);
  28. static NXColor RandomColor();
  29.  
  30. /* the kind of Maze view that appears in the control panel */
  31. @implementation StaticMazeView
  32.  
  33. - initMaze
  34. {
  35.     /* frame the field 2 cells bigger than the view */
  36.     ncols=MIN((((int)bounds.size.width-wallSize)/cellSize+2),MAXCOLS);
  37.     nrows=MIN((((int)bounds.size.height-wallSize)/cellSize+2),MAXROWS);
  38.     xoffset=((int)bounds.size.width-(ncols-2)*cellSize-wallSize)/2;
  39.     yoffset=((int)bounds.size.height-(nrows-2)*cellSize-wallSize)/2;
  40.  
  41.     /* allocate grid */
  42.     if (Grid) NXZoneFree([self zone],Grid);
  43.     NX_ZONEMALLOC([self zone],Grid,mazecell,nrows*ncols);
  44.  
  45.     [self computeMaze];
  46.  
  47.     /* choose a random starting place and direction */
  48.     icur=(random()%(ncols-2)+1)+(random()%(nrows-2)+1)*ncols;
  49.     dcur=random()%4;
  50.     Grid[icur].bdir=4;
  51.     ifirst=icur;
  52.     Grid[icur].next=(-1);
  53.  
  54.     /* set the current colors */
  55.     curWallColor=wallColor;
  56.     curPathColor=pathColor;
  57.  
  58.     /* clear drawing buffers */
  59.     wallRectListSize=0;
  60.     pathRectListSize=0;
  61.  
  62.     /* quickly do half-of-a-maze-exploration */
  63.     countDown=((nrows-2)*(ncols-2)*2-2)/2;
  64.     while (countDown--) {
  65.         int inew;
  66.         inew=icur;
  67.         switch (dcur) {
  68.         case 0:
  69.             if (!Grid[icur].eastwall) {dcur=0; inew=icur+1; break;}
  70.         case 1:
  71.             if (!Grid[icur].northwall) {dcur=1; inew=icur+ncols; break;}
  72.         case 2:
  73.             if (!Grid[icur].westwall) {dcur=2; inew=icur-1; break;}
  74.         case 3:
  75.             if (!Grid[icur].southwall) {dcur=3; inew=icur-ncols; break;}
  76.             if (!Grid[icur].eastwall) {dcur=0; inew=icur+1; break;}
  77.             if (!Grid[icur].northwall) {dcur=1; inew=icur+ncols; break;}
  78.             if (!Grid[icur].westwall) {dcur=2; inew=icur-1; break;}
  79.         }
  80.         if (Grid[icur].bdir==dcur) {
  81.             Grid[icur].bdir=(-1);
  82.         } else {
  83.             Grid[inew].next=ifirst;
  84.             ifirst=inew;
  85.             Grid[inew].bdir=dcur^2;
  86.         }
  87.         icur=inew;
  88.         dcur=(dcur+3)%4;
  89.     }
  90.  
  91.     return self;
  92. }
  93.  
  94. /* main view can tell panel view what colors to use */
  95. - setWallColor:(NXColor)wc pathColor:(NXColor)pc
  96. {
  97.     curWallColor=wallColor=wc;
  98.     curPathColor=pathColor=pc;
  99.     return self;
  100. }
  101.  
  102. @end
  103.  
  104.  
  105.  
  106.  
  107.  
  108.  
  109. @implementation MazeView
  110.  
  111. - initMaze
  112. {
  113.     /* frame the field 2 cells bigger than the view */
  114.     ncols=MIN((((int)bounds.size.width-wallSize)/cellSize+2),MAXCOLS);
  115.     nrows=MIN((((int)bounds.size.height-wallSize)/cellSize+2),MAXROWS);
  116.     xoffset=random()%((int)bounds.size.width-(ncols-2)*cellSize-wallSize+1);
  117.     yoffset=random()%((int)bounds.size.height-(nrows-2)*cellSize-wallSize+1);
  118.  
  119.     /* allocate grid */
  120.     if (Grid) NXZoneFree([self zone],Grid);
  121.     NX_ZONEMALLOC([self zone],Grid,mazecell,nrows*ncols);
  122.  
  123.     [self computeMaze];
  124.     countDown=(-1);
  125.     ifirst=(-1);
  126.     return self;
  127. }
  128.  
  129. - computeMaze
  130. {    
  131.     RandomIntPicker *picker;
  132.  
  133.     /* clear the "last" fields */
  134.     [self clearMaze];
  135.  
  136.     /* compute the maze */
  137.     icur=(random()%(ncols-2)+1)+(random()%(nrows-2)+1)*ncols;
  138.     Grid[icur].bdir=4;
  139.     Grid[icur].eastwall=Grid[icur].northwall=
  140.         Grid[icur].westwall=Grid[icur].southwall=1;
  141.     picker=[[RandomIntPicker alloc] init];
  142.     while (1) {
  143.         [picker reset];
  144.         if (Grid[icur+1].bdir<0) [picker insert:0];
  145.         if (Grid[icur+ncols].bdir<0) [picker insert:1];
  146.         if (Grid[icur-1].bdir<0) [picker insert:2];
  147.         if (Grid[icur-ncols].bdir<0) [picker insert:3];
  148.         if ([picker count]) {
  149.             switch ([picker choice]) {
  150.             case 0: icur=icur+1; break;
  151.             case 1: icur=icur+ncols; break;
  152.             case 2: icur=icur-1; break;
  153.             case 3: icur=icur-ncols; break;
  154.             }
  155.             Grid[icur].bdir=([picker choice]+2)%4;
  156.             Grid[icur].eastwall=Grid[icur].northwall=
  157.                 Grid[icur].westwall=Grid[icur].southwall=1;
  158.         } else {
  159.             switch (Grid[icur].bdir) {
  160.             case 0: Grid[icur].eastwall=0; icur=icur+1;
  161.                 Grid[icur].westwall=0; break;
  162.             case 1: Grid[icur].northwall=0; icur=icur+ncols;
  163.                 Grid[icur].southwall=0; break;
  164.             case 2: Grid[icur].westwall=0; icur=icur-1;
  165.                 Grid[icur].eastwall=0; break;
  166.             case 3: Grid[icur].southwall=0; icur=icur-ncols;
  167.                 Grid[icur].northwall=0; break;
  168.             case 4: goto finish;
  169.             }
  170.         }
  171.     }
  172.  finish:
  173.     [picker free];
  174.  
  175.     /* walls are set; clear the "last" fields again */
  176.     [self clearMaze];
  177.  
  178.     return self;
  179. }
  180.  
  181. - firstStep
  182. {
  183.     /* choose a random starting place and direction */
  184.     icur=(random()%(ncols-2)+1)+(random()%(nrows-2)+1)*ncols;
  185.     dcur=random()%4;
  186.     Grid[icur].bdir=4;
  187.     ifirst=icur;
  188.     Grid[icur].next=(-1);
  189.  
  190.     /* set the current colors */
  191.     if (randomColor) {
  192.         curWallColor=RandomColor();
  193.         curPathColor=RandomColor();
  194.     } else {
  195.         curWallColor=wallColor;
  196.         curPathColor=pathColor;
  197.     }
  198.  
  199.     if (sharedInspectorPanel) {
  200.         if (panelMazeView) {
  201.             [panelMazeView setWallColor:curWallColor pathColor:curPathColor];
  202.         }
  203.         [sharedInspectorPanel display];
  204.     }
  205.  
  206.     /* clear drawing buffers */
  207.     wallRectListSize=0;
  208.     pathRectListSize=0;
  209.  
  210.     /* clear drawing etc */
  211.     [self lockFocus];
  212.     PSsetgray(NX_BLACK);
  213.     NXRectFill(&bounds);
  214.     [self drawForward:icur];
  215.     [self flushDrawing];
  216.     [self unlockFocus];
  217.  
  218.     /* start countDown */
  219.     countDown=(nrows-2)*(ncols-2)*2-2;
  220.  
  221.     return self;
  222. }
  223.  
  224. /* here's where the maze solving and drawing is done */
  225. - oneStep
  226. {
  227.     int inew;
  228.     BStimeval curtime;
  229.  
  230.     /* enforce the delay between frames */
  231.     curtime=currentTimeInMs();
  232.     if (curtime-lasttime<delay) {
  233.         if (curtime-lasttime-delay>30) return self;
  234.         usleep((delay-(curtime-lasttime))*1000);
  235.         curtime=currentTimeInMs();
  236.     }
  237.     lasttime=curtime;
  238.  
  239.     /* check if finished */
  240.     if (countDown<=0) {
  241.         /* do the following only when recycling, not when running 1st time */
  242.         if (!countDown) {
  243.             [self drawBack:icur];
  244.             [self flushDrawing];
  245.             if (panelMazeView) {
  246.                 [panelMazeView initMaze];
  247.             }
  248.             [self initMaze];
  249.         }
  250.         [self firstStep];
  251.         return self;
  252.     }
  253.     countDown--;
  254.  
  255.     /* follow-the-right-wall algorithm... switch fallthrough intentional */
  256.     inew=icur;
  257.  
  258.     switch (dcur) {
  259.     case 0:
  260.         if (!Grid[icur].eastwall) {dcur=0; inew=icur+1; break;}
  261.     case 1:
  262.         if (!Grid[icur].northwall) {dcur=1; inew=icur+ncols; break;}
  263.     case 2:
  264.         if (!Grid[icur].westwall) {dcur=2; inew=icur-1; break;}
  265.     case 3:
  266.         if (!Grid[icur].southwall) {dcur=3; inew=icur-ncols; break;}
  267.         if (!Grid[icur].eastwall) {dcur=0; inew=icur+1; break;}
  268.         if (!Grid[icur].northwall) {dcur=1; inew=icur+ncols; break;}
  269.         if (!Grid[icur].westwall) {dcur=2; inew=icur-1; break;}
  270.     }
  271.  
  272.     if (Grid[icur].bdir==dcur) {
  273.         [self drawBack:icur];
  274.         Grid[icur].bdir=(-1);
  275.     } else {
  276.         Grid[inew].next=ifirst;
  277.         ifirst=inew;
  278.         Grid[inew].bdir=dcur^2;
  279.         [self drawForward:inew];
  280.     }
  281.  
  282.     [self flushDrawing];
  283.  
  284.     icur=inew;
  285.     dcur=(dcur+3)%4;
  286.     return self;
  287. }
  288.  
  289.  
  290. - drawForward:(int) index
  291. {
  292.     int x,y;
  293.  
  294.     x=(index%ncols-1)*cellSize+xoffset;
  295.     y=(index/ncols-1)*cellSize+yoffset;
  296.     switch (Grid[index].bdir) {
  297.     case 0:
  298.         [self addPathRectOrigin: x+wallSize+gapSize:y+wallSize+gapSize
  299.                     size: cellSize:pathSize]; break;
  300.     case 1:
  301.         [self addPathRectOrigin: x+wallSize+gapSize:y+wallSize+gapSize
  302.                     size: pathSize:cellSize]; break;
  303.     case 2:
  304.         [self addPathRectOrigin: x-gapSize:y+wallSize+gapSize
  305.                     size: cellSize:pathSize]; break;
  306.     case 3:
  307.         [self addPathRectOrigin: x+wallSize+gapSize:y-gapSize
  308.                     size: pathSize:cellSize]; break;
  309.     case 4:
  310.         [self addPathRectOrigin:x+wallSize+gapSize:y+wallSize+gapSize
  311.               size: pathSize:pathSize]; break;
  312.     }
  313.  
  314.     if (Grid[index].eastwall && Grid[index+1].next==(-2)) {
  315.         [self addWallRectOrigin:x+cellSize:y size:wallSize:cellSize+wallSize];
  316.     }
  317.     if (Grid[index].northwall && Grid[index+ncols].next==(-2)) {
  318.         [self addWallRectOrigin:x:y+cellSize size:cellSize+wallSize:wallSize];
  319.     }
  320.     if (Grid[index].westwall) {
  321.         [self addWallRectOrigin:x:y size:wallSize:cellSize+wallSize];
  322.     }
  323.     if (Grid[index].southwall) {
  324.         [self addWallRectOrigin:x:y size:cellSize+wallSize:wallSize];
  325.     }
  326.  
  327.     return self;
  328. }
  329.  
  330. - drawBack:(int) index
  331. {
  332.     int x,y;
  333.  
  334.     x=(index%ncols-1)*cellSize+xoffset;
  335.     y=(index/ncols-1)*cellSize+yoffset;
  336.  
  337.     [self addEraseRectOrigin:x+wallSize+gapSize:y+wallSize+gapSize
  338.           size:pathSize:pathSize];
  339.  
  340.     switch (Grid[index].bdir) {
  341.     case 0:
  342.         [self addEraseRectOrigin: x+wallSize+gapSize:y+wallSize+gapSize
  343.                     size: cellSize:pathSize]; break;
  344.     case 1:
  345.         [self addEraseRectOrigin: x+wallSize+gapSize:y+wallSize+gapSize
  346.                     size: pathSize:cellSize]; break;
  347.     case 2:
  348.         [self addEraseRectOrigin: x-gapSize:y+wallSize+gapSize
  349.                     size: cellSize:pathSize]; break;
  350.     case 3:
  351.         [self addEraseRectOrigin: x+wallSize+gapSize:y-gapSize
  352.                     size: pathSize:cellSize]; break;
  353.     case 4:
  354.         [self addEraseRectOrigin:x+wallSize+gapSize:y+wallSize+gapSize
  355.               size: pathSize:pathSize]; break;
  356.     }
  357.  
  358.     return self;
  359. }
  360.  
  361. - addWallRectOrigin:(int) x :(int) y size:(int)w :(int) h
  362. {
  363.     wallRectList[wallRectListSize].origin.x=x;
  364.     wallRectList[wallRectListSize].origin.y=y;
  365.     wallRectList[wallRectListSize].size.height=h;
  366.     wallRectList[wallRectListSize].size.width=w;
  367.     if (++wallRectListSize>=RECTBUFSIZE) {
  368.         [self flushWallRects];
  369.     }
  370.     return self;
  371. }
  372.  
  373. - flushWallRects
  374. {
  375.     if (wallRectListSize) {
  376.         NXSetColor(curWallColor);
  377.         NXRectFillList(wallRectList, wallRectListSize);
  378.         wallRectListSize=0;
  379.     }
  380.     return self;
  381. }
  382.     
  383. - addPathRectOrigin:(int) x :(int) y size:(int)w :(int) h
  384. {
  385.     pathRectList[pathRectListSize].origin.x=x;
  386.     pathRectList[pathRectListSize].origin.y=y;
  387.     pathRectList[pathRectListSize].size.height=h;
  388.     pathRectList[pathRectListSize].size.width=w;
  389.     if (++pathRectListSize>=RECTBUFSIZE) {
  390.         [self flushPathRects];
  391.     }
  392.     return self;
  393. }
  394.  
  395. - flushPathRects
  396. {
  397.     if (pathRectListSize) {
  398.         NXSetColor(curPathColor);
  399.         NXRectFillList(pathRectList, pathRectListSize);
  400.         pathRectListSize=0;
  401.     }
  402.     return self;
  403. }
  404.  
  405. - addEraseRectOrigin:(int) x :(int) y size:(int)w :(int) h
  406. {
  407.     eraseRectList[eraseRectListSize].origin.x=x;
  408.     eraseRectList[eraseRectListSize].origin.y=y;
  409.     eraseRectList[eraseRectListSize].size.height=h;
  410.     eraseRectList[eraseRectListSize].size.width=w;
  411.     if (++eraseRectListSize>=RECTBUFSIZE) {
  412.         [self flushEraseRects];
  413.     }
  414.     return self;
  415. }
  416.  
  417. - flushEraseRects
  418. {
  419.     if (eraseRectListSize) {
  420.         PSsetgray(NX_BLACK);
  421.         NXRectFillList(eraseRectList, eraseRectListSize);
  422.         eraseRectListSize=0;
  423.     }
  424.     return self;
  425. }
  426.  
  427. - flushDrawing
  428. {
  429.     [self flushWallRects];
  430.     [self flushPathRects];
  431.     [self flushEraseRects];
  432.     return self;
  433. }
  434.         
  435. - drawSelf:(const NXRect *)rects :(int)rectCount
  436. {
  437.     int i;
  438.  
  439.     PSsetgray(NX_BLACK);
  440.     if (rectCount>1) {
  441.         while(--rectCount) {
  442.             NXRectFill(rects+rectCount);
  443.         }
  444.     } else {
  445.         NXRectFill(rects);
  446.     }
  447.     for (i=ifirst; i>=0; i=Grid[i].next) {
  448.         [self drawForward:i];
  449.     }
  450.     [self flushDrawing];
  451.     return self;
  452. }
  453.  
  454. - (const char *) windowTitle
  455. {    return "Maze";
  456. }
  457.  
  458. - initFrame:(const NXRect *)frameRect
  459. {
  460.     [super initFrame:frameRect];
  461.     
  462.     Grid=NULL;
  463.     [self getMazeDefaults];
  464.     srandom(time(NULL));
  465.     [self initMaze];
  466.  
  467.     return self;
  468. }
  469.  
  470. - free
  471. {
  472.     if (Grid) NXZoneFree([self zone], Grid);
  473.     Grid=NULL;
  474.     return [super free];
  475. }
  476.  
  477. static void ColorToString(NXColor color, char *str)
  478. {
  479.     sprintf(str,"%f %f %f",NXRedComponent(color),
  480.             NXGreenComponent(color),NXBlueComponent(color));
  481. }
  482.  
  483. static NXColor ColorFromString(const char *str)
  484. {
  485.     NXColor color;
  486.     float r,g,b;
  487.     sscanf(str,"%f %f %f",&r,&g,&b);
  488.     r=(r<0.0 ? 0.0 : (r>1.0 ? 1.0 : r));
  489.     g=(g<0.0 ? 0.0 : (g>1.0 ? 1.0 : g));
  490.     b=(b<0.0 ? 0.0 : (b>1.0 ? 1.0 : b));
  491.     color=NXConvertRGBToColor(r,g,b);
  492.     return color;
  493. }
  494.  
  495. static NXColor RandomColor()
  496. {
  497.     NXColor color;
  498.     float r,g,b;
  499.     r=((random()%65536)/65536.0)/2;
  500.     g=((random()%65536)/65536.0)/2;
  501.     b=((random()%65536)/65536.0)/2;
  502.     color=NXConvertRGBToColor(r,g,b);
  503.     return color;
  504. }
  505.  
  506. - getMazeDefaults
  507. {
  508.     char c;
  509.  
  510.     static NXDefaultsVector MazeDefaults = {
  511.         {"MazeFrameDelay",  "16"},
  512.         {"MazeRandomColor", "No"},
  513.         {"MazeWallColor", "0.000000 0.000000 0.666662"},
  514.         {"MazePathColor","0.666662 0.666662 0.000000"},
  515.         {"MazeWallSize",   "2"},
  516.         {"MazePathSize",   "4"},
  517.         {"MazeGapSize",    "1"},
  518.         {NULL}
  519.     };
  520.     
  521.     NXRegisterDefaults("BackSpace",MazeDefaults);
  522.     sscanf(NXGetDefaultValue("BackSpace","MazeFrameDelay"),"%d",&delay);
  523.     if (delay<0) delay=0;
  524.     if (delay>MAXDELAY) delay=MAXDELAY;
  525.     if ((c=*NXGetDefaultValue("BackSpace","MazeRandomColor"))=='y' || c=='Y') {
  526.         randomColor=YES;
  527.     } else {
  528.         randomColor=NO;
  529.     }
  530.     wallColor=
  531.       ColorFromString(NXGetDefaultValue("BackSpace","MazeWallColor"));
  532.     pathColor=
  533.       ColorFromString(NXGetDefaultValue("BackSpace","MazePathColor"));
  534.     sscanf(NXGetDefaultValue("BackSpace","MazeWallSize"),"%d",&wallSize);
  535.     sscanf(NXGetDefaultValue("BackSpace","MazePathSize"),"%d",&pathSize);
  536.     sscanf(NXGetDefaultValue("BackSpace","MazeGapSize"),"%d",&gapSize);
  537.     cellSize=pathSize+wallSize+2*gapSize;
  538.     if (cellSize<MINCELLSIZE) {
  539.         pathSize+=MINCELLSIZE-cellSize;
  540.         cellSize=MINCELLSIZE;
  541.     }
  542.  
  543.     return self;
  544. }
  545.  
  546.  
  547. - sizeTo:(NXCoord)width :(NXCoord)height
  548. {
  549.     [super sizeTo:width :height];
  550.     [self initMaze];
  551.     return self;
  552. }
  553.  
  554. - clearMaze
  555. {
  556.     int x,y;
  557.  
  558.     icur = -1;
  559.  
  560.     /* clear the field */
  561.     for (y=0; y<nrows; y++) {
  562.         for (x=0; x<ncols; x++) {
  563.             if (x==0 || y==0 || x==ncols-1 || y==nrows-1) {
  564.                 Grid[x+y*ncols].bdir=4;
  565.             } else {
  566.                 Grid[x+y*ncols].bdir=(-1);
  567.             }
  568.             Grid[x+y*ncols].next=(-2);
  569.     }
  570.     }
  571.  
  572.     return self;
  573. }
  574.  
  575.  
  576. /* quick update called when color has been changed */
  577. - updateViews
  578. {
  579.     /* update the panel view, if needed */
  580.     if (sharedInspectorPanel) {
  581.         if (panelMazeView) {
  582.             [panelMazeView setWallColor:curWallColor pathColor:curPathColor];
  583.         }
  584.         [sharedInspectorPanel display];
  585.     }
  586.  
  587.     /* update myself */
  588.  
  589.     [self lockFocus];
  590.     [self display];
  591.     [self unlockFocus];
  592.  
  593.     return self;
  594. }
  595.  
  596. - inspector:sender
  597. {
  598.     char buf[MAXPATHLEN];
  599.     if (!sharedInspectorPanel) {
  600.         sprintf(buf,"%s/MazeInspector.nib",[sender moduleDirectory:"Maze"]);
  601.         [NXApp loadNibFile:buf owner:self withNames:NO];
  602.         /* initialize some of the panel objects... */
  603.         if (panelWallColorWell) {
  604.             [panelWallColorWell setColor:wallColor];
  605.             [panelWallColorWell setEnabled:!randomColor];
  606.         }
  607.         if (panelPathColorWell) {
  608.             [panelPathColorWell setColor:pathColor];
  609.             [panelPathColorWell setEnabled:!randomColor];
  610.         }
  611.         if (randomColorSwitch) [randomColorSwitch setState:randomColor];
  612.         if (panelSpeedSlider)
  613.         [panelSpeedSlider setFloatValue:(float)(-log(delay/100.0)/log(100))];
  614.     }
  615.     return sharedInspectorPanel;
  616. }
  617.  
  618. - inspectorInstalled
  619. {
  620.     [self hideCredits:self];
  621.     if (sharedInspectorPanel) {
  622.         [sharedInspectorPanel display];
  623.     }
  624.     return self;
  625. }
  626.  
  627. - doRandomColorSwitch:sender
  628. {
  629.     if ([sender state]) {
  630.         [panelWallColorWell setEnabled:NO];
  631.         [panelPathColorWell setEnabled:NO];
  632.         randomColor=YES;
  633.         curWallColor=RandomColor();
  634.         curPathColor=RandomColor();
  635.         NXWriteDefault("BackSpace","MazeRandomColor","Yes");
  636.     } else {
  637.         [panelWallColorWell setEnabled:YES];
  638.         [panelPathColorWell setEnabled:YES];
  639.         randomColor=NO;
  640.         curWallColor=wallColor;
  641.         curPathColor=pathColor;
  642.         NXWriteDefault("BackSpace","MazeRandomColor","No");
  643.     }
  644.     [self updateViews];
  645.     return self;
  646. }
  647.  
  648. - doSpeedSlider:sender
  649. {
  650.     char str[80];
  651.     delay=100*exp(-[sender floatValue]*log(100));
  652.     sprintf(str,"%d",delay);
  653.     NXWriteDefault("BackSpace","MazeFrameDelay",str);
  654.     return self;
  655. }
  656.  
  657. - takeWallColorFrom:sender
  658. {
  659.     char str[80];
  660.     curWallColor=wallColor=[(NXColorWell *)sender color];
  661.     [self updateViews];
  662.     ColorToString(wallColor,str);
  663.     NXWriteDefault("BackSpace","MazeWallColor",str);
  664.     return self;
  665. }
  666.  
  667. - takePathColorFrom:sender
  668. {
  669.     char str[80];
  670.     curPathColor=pathColor=[(NXColorWell *)sender color];
  671.     [self updateViews];
  672.     ColorToString(pathColor,str);
  673.     NXWriteDefault("BackSpace","MazePathColor",str);
  674.     return self;
  675. }
  676.  
  677. - showCredits:sender
  678. {
  679.     if (panelCreditsView && sharedInspectorPanel) {
  680.         if ([panelCreditsView isDescendantOf:sharedInspectorPanel]) {
  681.             [panelCreditsView removeFromSuperview];
  682.         }
  683.         [sharedInspectorPanel addSubview:panelCreditsView];
  684.         [sharedInspectorPanel display];
  685.     }
  686.     return self;
  687. }
  688.  
  689. - hideCredits:sender
  690. {
  691.     if (panelCreditsView && sharedInspectorPanel) {
  692.         if ([panelCreditsView isDescendantOf:sharedInspectorPanel]) {
  693.             [panelCreditsView removeFromSuperview];
  694.         }
  695.         [sharedInspectorPanel display];
  696.     }
  697.     return self;
  698. }
  699.  
  700. /* these methods are needed because we should not rearrange the view */
  701. /* hierarchy while a button is active; we queue the rearranging to be */
  702. /* done later as an event, when nothing is locked on the view */
  703.  
  704. - doShowCredits:sender
  705. {
  706.     [self perform:@selector(showCredits:)
  707.           with:self afterDelay:0 cancelPrevious:YES];
  708.     return self;
  709. }
  710.  
  711. - doHideCredits:sender
  712. {
  713.     [self perform:@selector(hideCredits:)
  714.           with:self afterDelay:0 cancelPrevious:YES];
  715.     return self;
  716. }
  717.  
  718. @end
  719.  
  720.  
  721.